package example

import (
	"context"
	"fmt"
	"github.com/beherochuling/beesoft_api/app/helper/net"
	"github.com/gogf/gf/v2/frame/g"
	retry "github.com/grpc-ecosystem/go-grpc-middleware/retry"
	"google.golang.org/grpc"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/metadata"
	"io"
	"log"
	"strconv"
	"time"
)

func NewClient(ctx context.Context) *grpcClient {
	rootCaFile := g.Config().MustGet(ctx, "tls.rootCaFile").String()
	certFile := g.Config().MustGet(ctx, "tls.client.certFile").String()
	keyFile := g.Config().MustGet(ctx, "tls.client.certFile").String()

	retryOpt := []retry.CallOption{
		retry.WithMax(3), // 重试3次
		retry.WithPerRetryTimeout(1 * time.Second),                                // 超过1s重试
		retry.WithCodes(codes.Unknown, codes.DeadlineExceeded, codes.Unavailable), // 哪些状态码重试
	}

	opts := []grpc.DialOption{
		// grpc.WithTransportCredentials(insecure.NewCredentials()),
		grpc.WithTransportCredentials(net.NewTls(rootCaFile, certFile, keyFile).Server()),
		grpc.WithPerRPCCredentials(new(customCredential)),
		grpc.WithUnaryInterceptor(retry.UnaryClientInterceptor(retryOpt...)),
	}

	port := g.Config().MustGet(ctx, "grpc.port").String()
	conn, err := grpc.Dial(port, opts...)
	if err != nil {
		panic(err)
	}
	// defer func(conn *grpc.ClientConn) {
	// 	err := conn.Close()
	// 	if err != nil {
	// 		panic(err)
	// 	}
	// }(conn)

	return &grpcClient{
		conn: conn,
	}
}

type grpcClient struct {
	conn *grpc.ClientConn
}

func (r *grpcClient) General(ctx context.Context) { // 1. simple
	resp, err := pb.NewUserClient(r.conn).
		GetUser1(ctx, &pb.UserRequest{
			Id:   123,
			Name: "test",
		})
	if err != nil {
		panic(err)
	}

	fmt.Println("响应结果", resp)
}
func (r *grpcClient) ServerStream(ctx context.Context) { // 2. 服务端流
	user, err := pb.NewUserClient(r.conn).
		GetUser2(ctx, &pb.GetUserRequest{
			UserId: "1",
		})
	if err != nil {
		panic(err)
	}

	for {
		resp, err := user.Recv()
		if err == io.EOF {
			break
		}
		if err != nil {
			log.Fatalf("fail to recv: %v", err)
		}

		fmt.Printf("recv backend data:%s\n", resp)
	}
}
func (r *grpcClient) ClientStream(ctx context.Context) { // 3. 客户端流
	user3, err := pb.NewUserClient(r.conn).
		GetUser3(ctx)
	if err != nil {
		panic(err)
	}

	i := 0
	for {
		if i > 10 {
			break
		}
		i++
		time.Sleep(time.Second)
		err := user3.Send(&pb.GetUserRequest{
			UserId: strconv.Itoa(i),
		})
		fmt.Println("send:", i)
		if err != nil {
			log.Fatalf("fail to send: %v", err)
		}
	}
	// 客户端结束发送
	resp3, err := user3.CloseAndRecv()
	if err != nil {
		log.Fatalf("fail to close: %v", err)
	}
	fmt.Println(resp3)
}
func (r *grpcClient) Stream(ctx context.Context) { // 4. 双流
	user4, err := pb.NewUserClient(r.conn).
		GetUser4(ctx)
	if err != nil {
		panic(err)
	}

	for i := 0; i < 10; i++ {
		time.Sleep(time.Second)
		err := user4.Send(&pb.GetUserRequest{UserId: strconv.Itoa(i)})
		if err != nil {
			log.Fatalf("fail to send: %v", err)
		}

		resp, err := user4.Recv()
		if err != nil {
			log.Fatalf("fail to recv: %v", err)
		}
		fmt.Printf("%v\n", resp)
	}

	err = user4.CloseSend()
	if err != nil {
		log.Fatalf("fail to close send: %v", err)
	}

	// wg := sync.WaitGroup{}
	// wg.Add(2)
	// defer wg.Wait()
	//
	// allstream, _ := client.AllStream(ctx)
	//
	// go func() {
	// 	defer wg.Done()
	// 	for i := 0; i < 10; i++ {
	// 		StreamResData, _ := allstream.Recv()
	// 		fmt.Println("AllStream收到服务端消息", StreamResData.Data)
	// 	}
	// }()
	//
	// go func() {
	// 	defer wg.Done()
	// 	StreamReqData.Data = "AllStream：我是客户端"
	// 	for i := 0; i < 10; i++ {
	// 		_ = allstream.Send(StreamReqData)
	// 		time.Sleep(time.Second)
	// 	}
	// }()
}
func (r *grpcClient) A(ctx context.Context) {
	md := metadata.Pairs("timestamp", time.Now().Format("YY"))
	md = metadata.New(map[string]string{
		"name": "chenteng",
	})
	ctx = metadata.NewOutgoingContext(ctx, md)
	fmt.Println(ctx)
}
